<?php
class CObjectExtendable
{
	// extended objects
	var $_aExtended =     array();
	
	// add extension
	function _extend($oObject)
	{
		if (is_object($oObject)) {
			$this->_aExtended[] = $oObject;
		} else if (is_array($oObject)) {
			$this->_aExtended = array_merge($this->_aExtended, $oObject);
		}
	}

	// override __get, __set and __call
	function __get($sName)
	{
		// start off with no object
		foreach ($this->_aExtended as $oObject) {
			// check it out
			if (property_exists($oObject, $sName)) {
				$sValue = $oObject->$sName;
				return $sValue;
			}
		}
		
		return 'Not found';
	}
	
	function __set($sName, $sValue)
	{
		// loop through objects
		foreach ($this->_aExtended as $oObject) {
			// first try property
			if (property_exists($oObject, $sName)) {
				return $oObject->$sName = $sValue;
			}
		}
	}
	
	function __call($sName, $aArgs = array())
	{
		// try method?
		if (method_exists($this, $sName)) {
			$return = call_user_func_array(array($this, $sName), $aArgs);
			return $return;
		}
		
		// loop through objects
		foreach ($this->_aExtended as $sLibrary => $oObject) {
			// callable?
			if (method_callable($oObject, $sName)) {
				$return = call_user_func_array(array($oObject, $sName), $aArgs);
				return $return;
			}
		}
		
		// does it exist as _$sName
		if (method_exists($this, '_' . $sName)) {
			$return = call_user_func_array(array($this, '_' . $sName), $aArgs);
			return $return;
		}
 
		return NULL;
	}
}